hvm: Fix evtchn-to-fake-pci interrupt propagation.
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 8 Jan 2008 15:55:29 +0000 (15:55 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 8 Jan 2008 15:55:29 +0000 (15:55 +0000)
Previously the evtchn_upcall_pending flag would only ever be sampled
on VCPU0, possibly leading to long delays in deasserting the
fake-pci-device INTx line if the interrupt is actually delivered to
other than VCPU0.

Diagnosed by Ian Jackson <ian.jackson@eu.citrix.com>

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/irq.c
xen/arch/x86/hvm/svm/intr.c
xen/arch/x86/hvm/vmx/intr.c
xen/include/asm-x86/event.h
xen/include/asm-x86/hvm/irq.h

index dc35eda989dce0ca2869b1f5d0f9efca8b0bdd72..072452a861ae8e93883324d0528e382a4bbe03ec 100644 (file)
@@ -125,17 +125,13 @@ void hvm_isa_irq_deassert(
     spin_unlock(&d->arch.hvm_domain.irq_lock);
 }
 
-void hvm_set_callback_irq_level(void)
+static void hvm_set_callback_irq_level(struct vcpu *v)
 {
-    struct vcpu *v = current;
     struct domain *d = v->domain;
     struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
     unsigned int gsi, pdev, pintx, asserted;
 
-    /* Fast lock-free tests. */
-    if ( (v->vcpu_id != 0) ||
-         (hvm_irq->callback_via_type == HVMIRQ_callback_none) )
-        return;
+    ASSERT(v->vcpu_id == 0);
 
     spin_lock(&d->arch.hvm_domain.irq_lock);
 
@@ -177,6 +173,22 @@ void hvm_set_callback_irq_level(void)
     spin_unlock(&d->arch.hvm_domain.irq_lock);
 }
 
+void hvm_maybe_deassert_evtchn_irq(void)
+{
+    struct domain *d = current->domain;
+    struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+    if ( hvm_irq->callback_via_asserted &&
+         !vcpu_info(d->vcpu[0], evtchn_upcall_pending) )
+        hvm_set_callback_irq_level(d->vcpu[0]);
+}
+
+void hvm_assert_evtchn_irq(struct vcpu *v)
+{
+    if ( v->vcpu_id == 0 )
+        hvm_set_callback_irq_level(v);
+}
+
 void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
 {
     struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
@@ -349,13 +361,7 @@ struct hvm_intack hvm_vcpu_ack_pending_irq(
 
 int hvm_local_events_need_delivery(struct vcpu *v)
 {
-    struct hvm_intack intack;
-
-    /* TODO: Get rid of event-channel special case. */
-    if ( vcpu_info(v, evtchn_upcall_pending) )
-        intack = hvm_intack_pic(0);
-    else
-        intack = hvm_vcpu_has_pending_irq(v);
+    struct hvm_intack intack = hvm_vcpu_has_pending_irq(v);
 
     if ( likely(intack.source == hvm_intsrc_none) )
         return 0;
index 268f9004596b5270c3266e3066e644957edbca08..08bc897543e73f2317f01c8ae07685b5e93926de 100644 (file)
@@ -102,7 +102,7 @@ asmlinkage void svm_intr_assist(void)
 
     /* Crank the handle on interrupt state. */
     pt_update_irq(v);
-    hvm_set_callback_irq_level();
+    hvm_maybe_deassert_evtchn_irq();
 
     do {
         intack = hvm_vcpu_has_pending_irq(v);
index 9476155f2a0d0788d7e4cf8eb64b63f80f568e5f..a4eb205392af0d8f4baccb6a8162c35881c84bb3 100644 (file)
@@ -156,10 +156,8 @@ asmlinkage void vmx_intr_assist(void)
 
     /* Crank the handle on interrupt state. */
     pt_update_irq(v);
-
     vmx_dirq_assist(v);
-  
-    hvm_set_callback_irq_level();
+    hvm_maybe_deassert_evtchn_irq();
 
     do {
         intack = hvm_vcpu_has_pending_irq(v);
index 05671f7ef3320b1603cab732885ababd7b12e8d1..6b1bf6a52d04e7a87ce198bb472ac767e2eeb744 100644 (file)
@@ -30,7 +30,12 @@ static inline void vcpu_kick(struct vcpu *v)
 
 static inline void vcpu_mark_events_pending(struct vcpu *v)
 {
-    if ( !test_and_set_bit(0, &vcpu_info(v, evtchn_upcall_pending)) )
+    if ( test_and_set_bit(0, &vcpu_info(v, evtchn_upcall_pending)) )
+        return;
+
+    if ( is_hvm_vcpu(v) )
+        hvm_assert_evtchn_irq(v);
+    else
         vcpu_kick(v);
 }
 
index 5fd0db3b7dbb0b0e78689ed80f67161271a251b8..355928d3bae3e88400fc5aebe4da4d08c57caa0c 100644 (file)
@@ -152,7 +152,8 @@ void hvm_isa_irq_deassert(
 
 void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq);
 
-void hvm_set_callback_irq_level(void);
+void hvm_maybe_deassert_evtchn_irq(void);
+void hvm_assert_evtchn_irq(struct vcpu *v);
 void hvm_set_callback_via(struct domain *d, uint64_t via);
 
 /* Check/Acknowledge next pending interrupt. */